package com.cn.tous.auth.oauth2.serializer;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
import org.springframework.security.oauth2.core.OAuth2Token;
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationCode;

import java.io.IOException;

public class OAuth2AuthorizationSerializer extends StdSerializer<OAuth2Authorization> {

    public OAuth2AuthorizationSerializer() {
        super(OAuth2Authorization.class);
    }

    @Override
    public void serialize(OAuth2Authorization auth, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        gen.writeStartObject();
        gen.writeStringField("id", auth.getId());
        gen.writeStringField("registeredClientId", auth.getRegisteredClientId());
        gen.writeStringField("principalName", auth.getPrincipalName());
        gen.writeStringField("authorizationGrantType", auth.getAuthorizationGrantType().getValue());

        // Tokens
        gen.writeObjectFieldStart("tokens");
        if (auth.getAccessToken() != null) {
            serializeToken(gen, "accessToken", auth.getAccessToken().getToken());
        }
        if (auth.getRefreshToken() != null) {
            serializeToken(gen, "refreshToken", auth.getRefreshToken().getToken());
        }

        gen.writeEndObject(); // tokens

        // Attributes
        gen.writeObjectFieldStart("attributes");
        auth.getAttributes().forEach((key, value) -> {
            try {
                if (value instanceof String || value instanceof Number || value instanceof Boolean) {
                    gen.writeObjectField(key, value);
                } else {
                    // 尽量序列化为字符串（如 UserDetails）
                    gen.writeStringField(key, value.toString());
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        });
        // attributes
        gen.writeEndObject();


        gen.writeEndObject();
    }

    private void serializeToken(JsonGenerator gen, String fieldName, OAuth2Token token) throws IOException {
        gen.writeObjectFieldStart(fieldName);
        gen.writeStringField("type", token.getClass().getName());
        gen.writeStringField("tokenValue", token.getTokenValue());

        if (token instanceof OAuth2AccessToken accessToken) {
            gen.writeStringField("tokenType", accessToken.getTokenType().getValue());
            if (accessToken.getIssuedAt() != null) {
                gen.writeNumberField("issuedAt", accessToken.getIssuedAt().toEpochMilli());
            }
            if (accessToken.getExpiresAt() != null) {
                gen.writeNumberField("expiresAt", accessToken.getExpiresAt().toEpochMilli());
            }
            // scopes
            gen.writeArrayFieldStart("scopes");
            for (String code: accessToken.getScopes()) {
                gen.writeString(code);
            }
//            accessToken.getScopes().forEach(gen::writeString);
            gen.writeEndArray();
        }

        if (token instanceof OAuth2RefreshToken refreshToken) {
            gen.writeNumberField("issuedAt", refreshToken.getIssuedAt().toEpochMilli());
        }

        if (token instanceof OAuth2AuthorizationCode code) {
            gen.writeNumberField("issuedAt", code.getIssuedAt().toEpochMilli());
            gen.writeNumberField("expiresAt", code.getExpiresAt().toEpochMilli());
        }

        gen.writeEndObject();
    }

}
